package cc.rengu.igas.channel.alipay.core.service.trans;

import cc.rengu.igas.channel.alipay.common.constant.AlipayConfigConstant;
import cc.rengu.igas.channel.alipay.common.constant.AlipayParamConstant;
import cc.rengu.igas.channel.alipay.common.constant.AlipayTreeNodeConstant;
import cc.rengu.igas.channel.alipay.common.enums.RespCodeEnum;
import cc.rengu.igas.channel.alipay.core.model.ChnlBizResponse;
import cc.rengu.igas.channel.alipay.core.service.base.PayService;
import cc.rengu.igas.channel.alipay.facade.request.AliFundFreezeRequest;
import cc.rengu.igas.channel.alipay.facade.response.AliFundFreezeResponse;
import cc.rengu.jradp.schedule.Schedule;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.CertInfoMapper;
import cc.rengu.oltp.service.common.dao.SecPlanInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.CertInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.SecPlanInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.*;
import cc.rengu.oltp.service.common.enums.ChannelEnum;
import cc.rengu.oltp.service.common.enums.OltpRpcdEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.realize.SysParamService;
import cc.rengu.oltp.service.realize.impl.SysParamServiceImpl;
import cc.rengu.oltp.utility.util.ConvertUtil;
import cc.rengu.oltp.utility.util.DateUtil;
import cc.rengu.oltp.utility.util.StringUtil;
import cc.rengu.oltp.utility.util.XmlTreeUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayFundAuthOrderAppFreezeRequest;
import com.alipay.api.request.AlipayFundAuthOrderFreezeRequest;
import com.alipay.api.response.AlipayFundAuthOrderAppFreezeResponse;
import com.alipay.api.response.AlipayFundAuthOrderFreezeResponse;

import java.util.List;
import java.util.Optional;

/**
 * 资金冻结
 */
public class FundFreezeService extends PayService {

    @Override
    protected Object beforeBizProcess() throws Exception {
        AliFundFreezeRequest aliFundFreezeRequest = new AliFundFreezeRequest();
        ConvertUtil.convertOutput(aliFundFreezeRequest);
        return aliFundFreezeRequest;
    }

    @Override
    protected ChnlBizResponse callBizService(Object request) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        int iReturnCode = 0;
        AliFundFreezeResponse aliFundFreezeResponse = new AliFundFreezeResponse();
        AliFundFreezeRequest aliFundFreezeRequest = (AliFundFreezeRequest) request;
        String instId = aliFundFreezeRequest.getHeader().getInstId();
        DstChannelCfg dstChannelCfg = (DstChannelCfg) xmlTreeUtil.getXmlTreeObjectValue(AlipayTreeNodeConstant.DST_CHANNEL_CFG,DstChannelCfg.class);
        DstChannelInfo dstChannelInfo =(DstChannelInfo) xmlTreeUtil.getXmlTreeObjectValue(AlipayTreeNodeConstant.DST_CHANNEL_INFO,DstChannelInfo.class);

        ConvertUtil.convertInput(aliFundFreezeRequest);
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.TXN_NUM, aliFundFreezeRequest.getHeader().getTxnNum());

        /* 演示环境发送短信默认返回成功 */
        if (AppParamConstant.DEFAULT_ENV.equals(AppParamConstant.APPLICATION_ENV)) {
            ChnlBizResponse chnlBizResponse = new ChnlBizResponse();
            aliFundFreezeResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
            aliFundFreezeResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
            aliFundFreezeResponse.setAuthNo("2014070800002001550000014417");
            aliFundFreezeResponse.setFundAmount(aliFundFreezeRequest.getFreezeAmt());
            aliFundFreezeResponse.setChannelOrderId("2014070800032850551");
            aliFundFreezeResponse.setCreditAmount(aliFundFreezeRequest.getFreezeAmt());
            aliFundFreezeResponse.setGmtTrans(DateUtil.getCurrentDateTime("yyyy-MM-dd hh:mm:ss"));
            aliFundFreezeResponse.setPayerLogonId("2088102000275885");
            aliFundFreezeResponse.setPreAuthType("CREDIT_AUTH");
            aliFundFreezeResponse.setStatus("SUCCESS");
            chnlBizResponse.setResult(aliFundFreezeResponse);
            return chnlBizResponse;
        }

        /*NUAL:网联支付宝;UPAL:银联支付宝*/
        if(ChannelEnum.NUAL.getChannelType().equals(aliFundFreezeRequest.getChannelId())||
                ChannelEnum.UPAL.getChannelType().equals(aliFundFreezeRequest.getChannelId())){
            xmlTreeUtil.setXmlTreeStringValue(AlipayTreeNodeConstant.ALI_PAY_SCENE,AlipayTreeNodeConstant.ALI_BAR_CODE_PAY);
            xmlTreeUtil.setXmlTreeStringValue(AlipayTreeNodeConstant.ALI_METHOD,"alipay.fund.auth.order.freeze");
            xmlTreeUtil.setXmlTreeStringValue(AlipayTreeNodeConstant.ALIPAY_APPID,dstChannelCfg.getAppId());
            xmlTreeUtil.setXmlTreeStringValue(AlipayTreeNodeConstant.ALIPAY_FORMAT,"JSON");

            xmlTreeUtil.setXmlTreeStringValue(AlipayTreeNodeConstant.ALI_PAY_CONTENT_AUTH_CODE,aliFundFreezeRequest.getPayCode());
            xmlTreeUtil.setXmlTreeStringValue(AlipayTreeNodeConstant.OUT_REQUEST_NO,aliFundFreezeRequest.getReqTraceNo());
            xmlTreeUtil.setXmlTreeStringValue(AlipayTreeNodeConstant.PRODUCT_CODE,aliFundFreezeRequest.getProductCode());
            xmlTreeUtil.setXmlTreeStringValue(AlipayTreeNodeConstant.ALI_EXTRA_PARAM, JSON.toJSONString(aliFundFreezeRequest.getExtendParam()));
            xmlTreeUtil.setXmlTreeStringValue(AlipayTreeNodeConstant.ALIPAY_ORGPID, dstChannelCfg.getProviderMchntNo());

            SysParamService sysParamService = new SysParamServiceImpl();
            SysParam sysParam;
            if(ChannelEnum.NUAL.getChannelType().equals(aliFundFreezeRequest.getChannelId())){
                sysParam = sysParamService.getSysParamInfo(instId,AlipayConfigConstant.NUCC_ALIPAY_CONF_NODE,AlipayConfigConstant.ALIPAY_NOTICE_URL);
                if(sysParam == null){
                    rglog.error("未配置异步通知地址，请配置");
                    throw new BizException(RespCodeEnum.CONFIG_PARAM_NOT_EXIST.getRespCode(),RespCodeEnum.CONFIG_PARAM_NOT_EXIST.getRespDesc());
                }
                SysParam sysParamUrl = sysParamService.getSysParamInfo(aliFundFreezeRequest.getHeader().getInstId(),AlipayConfigConstant.NUCC_ALIPAY_URL_CONF_NODE,
                        aliFundFreezeRequest.getHeader().getTxnNum());

                xmlTreeUtil.setXmlTreeStringValue(AlipayTreeNodeConstant.DEFINE_HTTP_URL_NODE,sysParamUrl.getParamValue());
            }else {
                sysParam = sysParamService.getSysParamInfo(instId,AlipayConfigConstant.CUPS_ALIPAY_CONF_NODE,AlipayConfigConstant.ALIPAY_NOTICE_URL);
                if(sysParam == null){
                    rglog.error("未配置异步通知地址，请配置");
                }else {
                    xmlTreeUtil.setXmlTreeStringValue(AlipayTreeNodeConstant.NOTIFY_URL,sysParam.getParamValue());
                }
            }
            iReturnCode = schedule.callService(dstChannelInfo.getDstServiceName(),0);
        } else if (ChannelEnum.ALIP.getChannelType().equals(aliFundFreezeRequest.getChannelId())){
            return directFundFreeze(aliFundFreezeRequest, dstChannelInfo, dstChannelCfg);
        } else {
            rglog.error("不支持的通道选择，channelId:<{}>",aliFundFreezeRequest.getChannelId());
            throw new BizException(RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespCode(),RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespDesc());
        }
        if(xmlTreeUtil.isExist(AlipayTreeNodeConstant.DEFINE_HTTP_URL_NODE)) {
            xmlTreeUtil.deleteXmlTreeNode(AlipayTreeNodeConstant.DEFINE_HTTP_URL_NODE);
        }
        if (0 != iReturnCode && 98 != iReturnCode){
            rglog.error("调用支付宝服务失败，iReturnCode:<{}>",iReturnCode);
            throw new BizException(RespCodeEnum.CALL_BIZ_SERVICE_ERROR.getRespCode(),RespCodeEnum.CALL_BIZ_SERVICE_ERROR.getRespDesc());
        }else if (98 == iReturnCode){
            rglog.error("调用支付宝服务超时，iReturnCode:<{}>",iReturnCode);
            throw new BizException(RespCodeEnum.TIME_OUT_ERROR.getRespCode(),RespCodeEnum.TIME_OUT_ERROR.getRespDesc());
        }
        ConvertUtil.convertOutput(aliFundFreezeResponse);
        String code = xmlTreeUtil.getXmlTreeStringValue(AlipayTreeNodeConstant.ALI_RET_CODE);
        String msg = xmlTreeUtil.getXmlTreeStringValue(AlipayTreeNodeConstant.ALI_RET_MSG);
        String subCode = xmlTreeUtil.getXmlTreeStringValue(AlipayTreeNodeConstant.ALI_RET_SUBCODE);
        String subMsg = xmlTreeUtil.getXmlTreeStringValue(AlipayTreeNodeConstant.ALI_RET_SUBMSG);
        if(!AlipayParamConstant.AILPAY_SUCCESS_CODE.equals(code) &&  !"10003".equals(code)){
            rglog.error("调用第三方服务失败,respCode=[{}],respMsg=[{}]",code,msg);
            aliFundFreezeResponse.setRespCode((null == subCode)?code:subCode);
            aliFundFreezeResponse.setRespDesc((null == subMsg)?msg:subMsg);
        }else if("10003".equals(code)){
            //等待用户付款
            rglog.error("用户正在付款中，请查询交易状态");
            aliFundFreezeResponse.setRespCode(code);
            aliFundFreezeResponse.setRespDesc(msg);
        }else {
            aliFundFreezeResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
            aliFundFreezeResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
        }
        ChnlBizResponse chnlBizResponse = new ChnlBizResponse();
        chnlBizResponse.setResult(aliFundFreezeResponse);
        return chnlBizResponse;
    }

    @Override
    protected void afterBizProcess(ChnlBizResponse response) throws Exception {
        AliFundFreezeResponse aliFundFreezeResponse = (AliFundFreezeResponse) response.getResult();
        ConvertUtil.convertInput(aliFundFreezeResponse);
    }
    ChnlBizResponse directFundFreeze(AliFundFreezeRequest aliFundFreezeRequest, DstChannelInfo dstChannelInfo, DstChannelCfg dstChannelCfg) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        AliFundFreezeResponse aliFundFreezeResponse = new AliFundFreezeResponse();
        String instId = aliFundFreezeRequest.getHeader().getInstId();
        ChnlBizResponse chnlBizResponse = new ChnlBizResponse();
        /* 支付宝支付参数获取 */
        /* 获取支付宝通讯配置参数 */
        SysParamService sysParamService = new SysParamServiceImpl();
        /*获取请求url*/
        SysParam sysParam = sysParamService.getSysParamInfo(instId, AlipayConfigConstant.ALIPAY_CONF_NODE, AlipayConfigConstant.ALIPAY_PAY_NET_URL);
        if (null == sysParam || StringUtil.isEmptyOrNull(sysParam.getParamValue())) {
            rglog.error("未配置支付宝直连专线URL地址，请配置");
            throw new BizException(RespCodeEnum.CONFIG_PARAM_NOT_EXIST.getRespCode(), RespCodeEnum.CONFIG_PARAM_NOT_EXIST.getRespDesc());
        }
        String requestUrl = sysParam.getParamValue();
        /*互联网代理IP*/
        sysParam = sysParamService.getSysParamInfo(instId, AlipayConfigConstant.ALIPAY_CONF_NODE, AlipayConfigConstant.ALIPAY_PROXY_NET_IP);
        String proxyIp = (null == sysParam || StringUtil.isEmptyOrNull(sysParam.getParamValue())) ? null : sysParam.getParamValue().trim();
        /*互联网代理端口*/
        sysParam = sysParamService.getSysParamInfo(instId, AlipayConfigConstant.ALIPAY_CONF_NODE, AlipayConfigConstant.ALIPAY_PROXY_NET_PORT);
        String proxyPort = (null == sysParam || StringUtil.isEmptyOrNull(sysParam.getParamValue())) ? null : sysParam.getParamValue().trim();
        /*报文类型*/
        sysParam = sysParamService.getSysParamInfo(instId, AlipayConfigConstant.ALIPAY_CONF_NODE, AlipayConfigConstant.ALIPAY_MSG_TYPE);
        String msgType = (null == sysParam || StringUtil.isEmptyOrNull(sysParam.getParamValue())) ? "json" : sysParam.getParamValue().trim();
        /*字符集*/
        sysParam = sysParamService.getSysParamInfo(instId, AlipayConfigConstant.ALIPAY_CONF_NODE, AlipayConfigConstant.ALIPAY_CHARSET);
        String charset = (null == sysParam || StringUtil.isEmptyOrNull(sysParam.getParamValue())) ? "UTF-8" : sysParam.getParamValue().trim();
        /*签名验签方式*/
        sysParam = sysParamService.getSysParamInfo(instId, AlipayConfigConstant.ALIPAY_CONF_NODE, AlipayConfigConstant.ALIPAY_SIGN_TYPE);
        String signType = (null == sysParam || StringUtil.isEmptyOrNull(sysParam.getParamValue())) ? "RSA2" : sysParam.getParamValue().trim();
        /*异步通知地址*/
        sysParam = sysParamService.getSysParamInfo(instId,AlipayConfigConstant.ALIPAY_CONF_NODE,AlipayConfigConstant.ALIPAY_NOTICE_URL);
        String notifyUrl = (null == sysParam || StringUtil.isEmptyOrNull(sysParam.getParamValue()) ? "" : sysParam.getParamValue().trim());

        /* 根据通道安全计划获取安全计划 */
        String priKey = null;
        String pubKey = null;
        SecPlanInfoMapper secPlanInfoMapper = new SecPlanInfoMapperImpl();
        CertInfoMapper certInfoMapper = new CertInfoMapperImpl();
        List<SecPlanInfo> secPlanInfoList = secPlanInfoMapper.selectSecPlanInfoBySecPlanId(instId, dstChannelCfg.getSecPlanId());

        /* 获取签名验签证书（私钥） */
        Optional<SecPlanInfo> secPlanInfoOptSign = secPlanInfoList.stream().filter(item -> item.getSecPlanType().equals(AlipayParamConstant.SIGN_CERT_TYPE)).findFirst();
        if (secPlanInfoOptSign.isPresent()) {
            CertInfo certInfoPri = certInfoMapper.selectCertInfoByPrimaryKey(instId + secPlanInfoOptSign.get().getSecPlanId() + secPlanInfoOptSign.get().getSecPlanType());
            if (certInfoPri != null) {
                priKey = certInfoPri.getCertValue();
            }
        }

        /* 获取签名验签证书（公钥） */
        Optional<SecPlanInfo> secPlanInfoOpt = secPlanInfoList.stream().filter(item -> item.getSecPlanType().equals(AlipayParamConstant.VERIFY_CERT_TYPE)).findFirst();
        if (secPlanInfoOpt.isPresent()) {
            CertInfo certInfoPub = certInfoMapper.selectCertInfoByPrimaryKey(instId + secPlanInfoOpt.get().getSecPlanId() + secPlanInfoOpt.get().getSecPlanType());
            if (certInfoPub != null) {
                pubKey = certInfoPub.getCertValue();
            }
        }

        /* 调用支付宝开启代商户签约、创建应用事务 */
        rglog.debug("aliPayUrl = <{}>;appId = <{}>;priKey = <{}>;msgType = <{}>,charset = <{}>,pubKey = <{}>,signType = <{}>,proxyIp = <{}>,proxyPort = <{}>",
                requestUrl, dstChannelCfg.getAppId(), priKey, msgType, charset, pubKey, signType, proxyIp, proxyPort);
        AlipayClient alipayClient;
        if (StringUtil.isEmptyOrNull(proxyIp) || StringUtil.isEmptyOrNull(proxyPort)) {
            alipayClient = new DefaultAlipayClient(requestUrl, dstChannelCfg.getAppId(), priKey, msgType, charset, pubKey, signType);
        } else {
            alipayClient = new DefaultAlipayClient(requestUrl, dstChannelCfg.getAppId(), priKey, msgType, charset, pubKey, signType, proxyIp, proxyPort);
        }
        AlipayFundAuthOrderFreezeRequest request = new AlipayFundAuthOrderFreezeRequest();
        // 设置异步通知
        request.setNotifyUrl(notifyUrl);
        JSONObject bizContent = new JSONObject();
        bizContent.put("auth_code",aliFundFreezeRequest.getPayCode());
        bizContent.put("auth_code_type","bar_code");
        bizContent.put("out_order_no",aliFundFreezeRequest.getMchntOrderId());
        bizContent.put("out_request_no",aliFundFreezeRequest.getReqTraceNo());
        bizContent.put("order_title","预授权冻结");
        bizContent.put("amount",aliFundFreezeRequest.getFreezeAmt());
        bizContent.put("product_code",aliFundFreezeRequest.getProductCode());
        bizContent.put("payee_user_id",aliFundFreezeRequest.getExtendParam().getSecondaryMerchantId());
        bizContent.put("timeout_express",aliFundFreezeRequest.getTimeoutExpr());
        request.setBizContent(bizContent.toString());
        //此处传入商家应用授权第三方应用的 app_auth_token
        if (!StringUtil.isEmptyOrNull(aliFundFreezeRequest.getAppAuthToken())) {
            request.putOtherTextParam("app_auth_token", aliFundFreezeRequest.getAppAuthToken());
        }
        AlipayFundAuthOrderFreezeResponse response = alipayClient.execute(request);
        if (response.isSuccess()) {
            aliFundFreezeResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
            aliFundFreezeResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
            aliFundFreezeResponse.setAuthNo(response.getAuthNo());
            aliFundFreezeResponse.setFundAmount(response.getFundAmount());
            aliFundFreezeResponse.setChannelOrderId(response.getOperationId());
            aliFundFreezeResponse.setCreditAmount(response.getCreditAmount());
            aliFundFreezeResponse.setGmtTrans(DateUtil.formatDate(response.getGmtTrans()));
            aliFundFreezeResponse.setPayerLogonId(response.getPayerUserId());
            aliFundFreezeResponse.setPreAuthType(response.getPreAuthType());
            aliFundFreezeResponse.setStatus(response.getStatus());
        } else {
            aliFundFreezeResponse.setRespCode((null == response.getSubCode()) ? response.getCode() : response.getSubCode());
            aliFundFreezeResponse.setRespDesc((null == response.getSubMsg()) ? response.getMsg() : response.getSubMsg());
        }
        chnlBizResponse.setResult(aliFundFreezeResponse);
        return chnlBizResponse;
    }
}
